/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include "lvgl.h"
#include "hmi_config.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static int32_t anim_path_triangle(const lv_anim_t *a);
static void anim_bg_color_cb(void *var, int32_t v);

/**********************
 *  STATIC VARIABLES
 **********************/
static lv_obj_t *bg;
static lv_color_t cur_bg_color;
static lv_color_t target_bg_color;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
lv_obj_t *hmi_bg()
{
    return bg;
}

void hmi_bg_create()
{
    lv_obj_set_style_bg_opa(lv_layer_bottom(), LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(lv_layer_bottom(), lv_palette_lighten(LV_PALETTE_GREY, 4), 0);

    bg = lv_obj_create(lv_layer_bottom());
    lv_obj_remove_style_all(bg);
    lv_obj_set_style_bg_opa(bg, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(bg, lv_color_hex(HMI_BLUE), 0);
    lv_obj_set_size(bg, lv_pct(100), lv_pct(100));
    lv_obj_set_y(bg, HMI_BG_NORMAL);
}

uint32_t hmi_anim_bg(uint32_t color, int32_t y_new)
{
    int32_t y_act = lv_obj_get_y(bg);
    lv_color_t act_color = lv_obj_get_style_bg_color(bg, 0);
    if (y_new != HMI_BG_NORMAL && y_new == y_act && !lv_memcmp(&act_color, &color, sizeof(lv_color_t)))
        return 0;

    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, bg);
    lv_anim_set_delay(&a, 0);
    lv_anim_set_duration(&a, HMI_ANIM_TIME_BG);

    if ((y_new == HMI_BG_NORMAL && y_new == y_act) || (y_new == HMI_BG_NORMAL && y_act == HMI_BG_FULL))
    {
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
        lv_anim_set_values(&a, y_act, y_new);
        lv_anim_set_path_cb(&a, anim_path_triangle);
        lv_anim_start(&a);
    }
    else
    {
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
        lv_anim_set_values(&a, lv_obj_get_y(bg), y_new);
        lv_anim_start(&a);
    }

    cur_bg_color = lv_obj_get_style_bg_color(bg, 0);
    target_bg_color = lv_color_hex(color);

    lv_anim_set_exec_cb(&a, anim_bg_color_cb);
    lv_anim_set_path_cb(&a, lv_anim_path_linear);
    lv_anim_set_values(&a, 0, 255);
    lv_anim_start(&a);

    if (!HMI_ANIM_TIME_BG)
        lv_obj_set_style_bg_color(bg, target_bg_color, 0);

    return HMI_ANIM_TIME_BG;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static int32_t anim_path_triangle(const lv_anim_t *a)
{
    uint32_t step;
    int32_t ret = 0;
    if (a->duration == a->act_time)
    {
        ret = (int32_t)a->end_value;
    }
    else
    {
        if (a->act_time < a->duration / 2)
        {
            step = ((int32_t)a->act_time * 1024) / (a->duration / 2);
            int32_t new_value;
            new_value = (int32_t)step * (HMI_BG_SMALL - a->start_value);
            new_value = new_value >> 10;
            new_value += a->start_value;

            ret = (int32_t)new_value;
        }
        else
        {
            uint32_t t = a->act_time - a->duration / 2;
            step = ((int32_t)t * 1024) / (a->duration / 2);
            int32_t new_value;
            new_value = (int32_t)step * (a->end_value - HMI_BG_SMALL);
            new_value = new_value >> 10;
            new_value += HMI_BG_SMALL;

            ret = (int32_t)new_value;
        }
    }

    return ret;
}

static void anim_bg_color_cb(void *var, int32_t v)
{
    lv_color_t c = lv_color_mix(target_bg_color, cur_bg_color, v);
    lv_obj_set_style_bg_color(bg, c, 0);
}
